/*
 * Copyright 2004 original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jbfilter.impl;

import java.util.Date;

import org.jbfilter.core.CleaningStrategy;
import org.jbfilter.core.EnableStrategy;
import org.jbfilter.core.FilterComponent;
import org.jbfilter.core.JbfilterComparatorKeyword;
import org.jbfilter.core.TruncateUnit;
import org.jbfilter.core.fcomps.delegate.DateFilterComponentDelegate;
import org.jbfilter.core.fcomps.delegate.NullTestingEnableableDelegate;
import org.jbfilter.core.fcomps.logic.AndFilterComponent;
import org.jbfilter.core.fcomps.multiple.StartEndDateFilterComponent;
import org.jbfilter.core.fcomps.single.DateFilterComponent;

abstract class _StartEndDateFilterComponentImpl<E>
	implements
		StartEndDateFilterComponent<E> {

	private DateFilterComponent<E> startComp;
	private DateFilterComponent<E> endComp;
	private AndFilterComponent<E> andComp;

	//delegates
	private DateFilterComponentDelegate<E> dfcDelegate;
	private NullTestingEnableableDelegate nteDelegate;
	private boolean inverted;
	
	private static final boolean INCLUDE_BORDERS_DEFAULT = true;
	
	public _StartEndDateFilterComponentImpl() {
		dfcDelegate = new DateFilterComponentDelegate<E>();
		nteDelegate = new NullTestingEnableableDelegate();
		
		startComp = initDateFc();
		endComp = initDateFc();
		andComp = initAndFc();
		andComp.addFilterComponent(startComp);
		andComp.addFilterComponent(endComp);
		
		setIncludeBorders(INCLUDE_BORDERS_DEFAULT);
		
		// register to delegate
		dfcDelegate.add(startComp);
		dfcDelegate.add(endComp);
		nteDelegate.add(startComp);
		nteDelegate.add(endComp);
	}
	
	abstract protected DateFilterComponent<E> initDateFc();
	abstract protected AndFilterComponent<E> initAndFc();
	
	protected FilterComponent<E> getActiveFc() {
		Date startDate = startComp.getValue();
		Date endDate = endComp.getValue();
		FilterComponent<E> activeFc;
		if (startDate != null && endDate != null) {
			activeFc = andComp;
		} else if (startDate != null) {
			activeFc = startComp;
		} else if (endDate != null) {
			activeFc = endComp;
		} else {	// start and end date are null, take preferably the one which includes border (for null testing case)
			if (isIncludeBorderStartDate()) {
				activeFc = startComp;
			} else {
				activeFc = endComp;
			}
		}
		// reset inverted...
		dfcDelegate.setInverted(false);
		andComp.setInverted(false);
		// ... before setting inverted
		activeFc.setInverted(inverted);
		return activeFc;
	}
	protected DateFilterComponent<E> getStartComp() {
		return startComp;
	}
	protected DateFilterComponent<E> getEndComp() {
		return endComp;
	}
	@Override
	public void setEnabled(boolean enabled) {
		dfcDelegate.setEnabled(enabled);
		andComp.setEnabled(enabled);
	}
	@Override
	public boolean isEnabled() {
		return dfcDelegate.isEnabled();
	}
	@Override
	public boolean isActive() {
		return dfcDelegate.isActive();
	}
	@Override
	public void clean() {
		dfcDelegate.clean();
	}
	@Override
	public void setCleaningStrategy(CleaningStrategy cleaningStrategy) {
		dfcDelegate.setCleaningStrategy(cleaningStrategy);		
	}
	@Override
	public String getId() {
		return dfcDelegate.getId();
	}
	@Override
	public void setId(String id) {
		dfcDelegate.setId(id);
	}
	@Override
	public boolean isInverted() {
		return inverted;
	}
	@Override
	public void setInverted(boolean inverted) {
		this.inverted = inverted;
	}
	@Override
	public void setEnableStrategy(EnableStrategy enableStrategy) {
		dfcDelegate.setEnableStrategy(enableStrategy);
	}
	@Override
	public CleaningStrategy getCleaningStrategy() {
		return dfcDelegate.getCleaningStrategy();
	}
	@Override
	public EnableStrategy getEnableStrategy() {
		return dfcDelegate.getEnableStrategy();
	}
	@Override
	public void setNullTestingEnabled(boolean enabled) {
		nteDelegate.setNullTestingEnabled(enabled);
	}
	@Override
	public boolean isNullTestingEnabled() {
		return nteDelegate.isNullTestingEnabled();
	}
	@Override
	public String getPropertyPath() {
		return dfcDelegate.getPropertyPath();
	}
	@Override
	public void setPropertyPath(String propertyPath) {
		dfcDelegate.setPropertyPath(propertyPath);
	}
	@Override
	public Date getStartDate() {
		return startComp.getValue();
	}
	@Override
	public void setStartDate(Date startDate) {
		startComp.setValue(startDate);
	}
	@Override
	public Date getEndDate() {
		return endComp.getValue();
	}
	@Override
	public void setEndDate(Date endDate) {
		endComp.setValue(endDate);
	}
	@Override
	public void setIncludeBorderStartDate(boolean includeBorder) {
		JbfilterComparatorKeyword comparatorKeyword
			= includeBorder ? JbfilterComparatorKeyword.ge : JbfilterComparatorKeyword.gt;
		startComp.setComparatorKeyword(comparatorKeyword);
	}
	@Override
	public void setIncludeBorderEndDate(boolean includeBorder) {
		JbfilterComparatorKeyword comparatorKeyword
			= includeBorder ? JbfilterComparatorKeyword.le : JbfilterComparatorKeyword.lt;
		endComp.setComparatorKeyword(comparatorKeyword);
	}
	@Override
	public void setIncludeBorders(boolean includeBorder) {
		setIncludeBorderStartDate(includeBorder);
		setIncludeBorderEndDate(includeBorder);
	}
	@Override
	public boolean isIncludeBorderStartDate() {
		return startComp.getComparatorKeyword() == JbfilterComparatorKeyword.ge;
	}
	@Override
	public boolean isIncludeBorderEndDate() {
		return endComp.getComparatorKeyword() == JbfilterComparatorKeyword.le;
	}
	@Override
	public void setTruncate(TruncateUnit truncate) {
		dfcDelegate.setTruncate(truncate);
	}
	@Override
	public TruncateUnit getTruncate() {
		return dfcDelegate.getTruncate();
	}
}
